﻿using System;
using Simp.CodeModel;
using System.Windows.Controls;
using Simp.CodeModel.CoreFunctions.Sequences;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace Simp.GraphModel
{
	/// <summary>Encapsulate a function grouping graph elements.</summary>
	public class ElementGroupFunction : IElementProducerFunction
	{
		private const int SCALE_SCOPE = 300;
		private static readonly string[] PARAMETER_NAMES = new[] { "shapes" };

		#region IFunction Members
		string IFunction.FunctionName
		{
			get { return "ElementGroup"; }
		}

		string[] IFunction.ParameterNames
		{
			get { return PARAMETER_NAMES; }
		}

		IFunctionParameterBinding[] IFunction.DefaultParameterValues
		{
			get { return FunctionHelper.EmptyBindings; }
		}

		IFunction IFunction.Simplify(SimplificationMode simplificationMode, params IFunction[] parameters)
		{
			return null;
		}

		IFunction IFunction.AcceptVisitor(IFunctionVisitor visitor)
		{
			return null;
		}
		#endregion

		#region IElementProducerFunction Members
		UIElement IElementProducerFunction.Produce(params IFunction[] parameters)
		{
			FunctionHelper.ValidateParameters(new ElementGroupFunction(), parameters);

			IFunction function = parameters[0];
			ISequenceAccessor accessor = FunctionHelper.GetAccessor(function);

			//	If the parameter isn't a sequence, we fake one
			if (accessor == null)
			{
				ISequenceFunction sequence = new ExplicitSequenceFunction(1);

				accessor = sequence.GetAccessor(function);
			}

			Canvas canvas = new Canvas();

			foreach (IFunction itemFunction in
				new SyncSimplifyingSequenceAccessor(SimplificationMode.AllowApproximation, accessor))
			{
				UIElement element = GraphicHelper.Produce(itemFunction);

				if (element == null)
				{
					return null;
				}
				else
				{
					canvas.Children.Add(element);
				}
			}

			return canvas;
		}
		#endregion

		/// <summary>Tries to get shapes out of a sequence of shape-functions.</summary>
		/// <param name="parameters"></param>
		/// <returns></returns>
		public static Canvas TryGetCanvas(IFunction function)
		{
			UIElement element = GraphicHelper.Produce(function);

			if (element == null)
			{
				return null;
			}
			else
			{
				Canvas canvas = CreateCanvas();
				Canvas subCanvas = (Canvas)canvas.Children[0];

				subCanvas.Children.Add(element);

				return canvas;
			}
		}

		private static Canvas CreateCanvas()
		{
			Canvas canvas = new Canvas
			{
				Background = new SolidColorBrush(Colors.Gray)
			};
			Canvas subCanvas = new Canvas();

			canvas.SizeChanged += delegate
			{
				TransformGroup group = new TransformGroup();

				group.Children.Add(new ScaleTransform
				{
					ScaleX = canvas.ActualWidth / SCALE_SCOPE,
					ScaleY = -canvas.ActualHeight / SCALE_SCOPE
				});
				group.Children.Add(new TranslateTransform { X = canvas.ActualWidth / 2, Y = canvas.ActualHeight / 2 });
				subCanvas.RenderTransform = group;

				subCanvas.Clip = new RectangleGeometry(new Rect(-SCALE_SCOPE / 2, -SCALE_SCOPE / 2, SCALE_SCOPE, SCALE_SCOPE));
			};

			canvas.Children.Add(subCanvas);

			return canvas;
		}
	}
}